package com.aiti.lulian.workflow;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@TableName("dj_process_instance")
public class ProcessInstance {
    @TableId(value = "id", type = IdType.ASSIGN_ID)
    private String id;
    private String processDefinitionId;

    private String businessKey;


    private Date startTime;


    private Date endTime;


    private ProcessStatus status;


    private String currentNodeId;


    private String variablesJson;

    @TableField(exist = false)
    @JsonIgnore
    private Map<String, Object> variables;

    @TableField(exist = false)
    @JsonIgnore
    private ProcessDefinition processDefinition;

    public ProcessInstance() {
        this.status = ProcessStatus.RUNNING;
        this.startTime = new Date();
        this.variables = new HashMap<>();
    }

    public ProcessInstance(ProcessDefinition processDefinition, String businessKey, Map<String, Object> variables) {
        this();
        this.processDefinition = processDefinition;
        this.processDefinitionId = processDefinition.getId();
        this.businessKey = businessKey;
        if (variables != null) {
            this.variables.putAll(variables);
        }
        this.variablesJson = convertVariablesToJson();
    }

    public void complete() {
        this.status = ProcessStatus.COMPLETED;
        this.endTime = new Date();
        this.currentNodeId = null;
    }

    public void terminate() {
        this.status = ProcessStatus.TERMINATED;
        this.endTime = new Date();
    }

    public void suspend() {
        this.status = ProcessStatus.SUSPENDED;
    }

    public void resume() {
        this.status = ProcessStatus.RUNNING;
    }

    public boolean isActive() {
        return status == ProcessStatus.RUNNING;
    }

    public boolean isCompleted() {
        return status == ProcessStatus.COMPLETED;
    }

    public boolean isTerminated() {
        return status == ProcessStatus.TERMINATED;
    }

    public boolean isSuspended() {
        return status == ProcessStatus.SUSPENDED;
    }

    public void setVariable(String key, Object value) {
        variables.put(key, value);
        this.variablesJson = convertVariablesToJson();
    }

    public Object getVariable(String key) {
        return variables.get(key);
    }

    @SuppressWarnings("unchecked")
    public <T> T getVariable(String key, Class<T> clazz) {
        Object value = variables.get(key);
        return clazz.isInstance(value) ? clazz.cast(value) : null;
    }

    public void removeVariable(String key) {
        variables.remove(key);
        this.variablesJson = convertVariablesToJson();
    }

    public boolean hasVariable(String key) {
        return variables.containsKey(key);
    }

    private String convertVariablesToJson() {
        try {
            ObjectMapper mapper = new ObjectMapper();
            return mapper.writeValueAsString(variables);
        } catch (JsonProcessingException e) {
            throw new RuntimeException("解析失败", e);
        }
    }

    private Map<String, Object> convertJsonToVariables(String json) {
        try {
            if (json == null || json.trim().isEmpty()) {
                return new HashMap<>();
            }
            ObjectMapper mapper = new ObjectMapper();
            return mapper.readValue(json, new TypeReference<Map<String, Object>>() {});
        } catch (Exception e) {
            throw new RuntimeException("解析失败", e);
        }
    }

    @JsonIgnore
    public String getProcessDefinitionName() {
        return processDefinition != null ? processDefinition.getName() : null;
    }


    public String getId() { return id; }
    public void setId(String id) { this.id = id; }

    public String getProcessDefinitionId() { return processDefinitionId; }
    public void setProcessDefinitionId(String processDefinitionId) { this.processDefinitionId = processDefinitionId; }

    public String getBusinessKey() { return businessKey; }
    public void setBusinessKey(String businessKey) { this.businessKey = businessKey; }

    public Date getStartTime() { return startTime; }
    public void setStartTime(Date startTime) { this.startTime = startTime; }

    public Date getEndTime() { return endTime; }
    public void setEndTime(Date endTime) { this.endTime = endTime; }

    public ProcessStatus getStatus() { return status; }
    public void setStatus(ProcessStatus status) { this.status = status; }

    public String getCurrentNodeId() { return currentNodeId; }
    public void setCurrentNodeId(String currentNodeId) { this.currentNodeId = currentNodeId; }

    public String getVariablesJson() { return variablesJson; }
    public void setVariablesJson(String variablesJson) {
        this.variablesJson = variablesJson;
        this.variables = convertJsonToVariables(variablesJson);
    }

    @JsonIgnore
    public Map<String, Object> getVariables() {
        if (variables == null && variablesJson != null) {
            variables = convertJsonToVariables(variablesJson);
        }
        return variables != null ? new HashMap<>(variables) : new HashMap<>();
    }

    public void setVariables(Map<String, Object> variables) {
        this.variables = variables != null ? new HashMap<>(variables) : new HashMap<>();
        this.variablesJson = convertVariablesToJson();
    }

    @JsonIgnore
    public ProcessDefinition getProcessDefinition() { return processDefinition; }
    public void setProcessDefinition(ProcessDefinition processDefinition) {
        this.processDefinition = processDefinition;
        if (processDefinition != null) {
            this.processDefinitionId = processDefinition.getId();
        }
    }

    public String getStatusText() {
        switch (status) {
            case RUNNING: return "运行中";
            case COMPLETED: return "已完成";
            case TERMINATED: return "已终止";
            case SUSPENDED: return "已挂起";
            default: return "未知";
        }
    }

    public long getDuration() {
        if (startTime == null) return 0;
        Date end = endTime != null ? endTime : new Date();
        return end.getTime() - startTime.getTime();
    }

    public String getFormattedDuration() {
        long duration = getDuration();
        long seconds = duration / 1000;
        long minutes = seconds / 60;
        long hours = minutes / 60;
        long days = hours / 24;

        if (days > 0) {
            return days + "天" + (hours % 24) + "小时";
        } else if (hours > 0) {
            return hours + "小时" + (minutes % 60) + "分钟";
        } else if (minutes > 0) {
            return minutes + "分钟" + (seconds % 60) + "秒";
        } else {
            return seconds + "秒";
        }
    }


}